#include "soft_timer.h"
#include <stdio.h>

#include "FreeRTOS.h"
#include "task.h"

static soft_timer_t timers_array[SOFT_TIMER_MAX];

void soft_timer_init() {
	
	for(int i = 0; i < SOFT_TIMER_MAX;i++) {
		timers_array[i].callback_ = NULL;
		timers_array[i].param_ = NULL;
		timers_array[i].state_ = SOFT_TIMER_IDLE;
		timers_array[i].count_ = 0;
		timers_array[i].match_ = 0;
		timers_array[i].period_ = 0;
	}
}

int8_t soft_timer_register(uint32_t period,timer_callback callback,void *param) {
	
	vTaskSuspendAll();
	int ret = -1;
	for(int i = 0; i < SOFT_TIMER_MAX;i++) {
		if(timers_array[i].state_ == SOFT_TIMER_IDLE) {
			timers_array[i].state_ = SOFT_TIMER_STOPPED;
			timers_array[i].period_ = period;
			timers_array[i].callback_ = callback;
			timers_array[i].param_ = param;
			ret = i;
			break;
		}
	}
	
	xTaskResumeAll();
	return ret;
}

void soft_timer_unregister(int8_t id) {
	
	vTaskSuspendAll();
	if(id < SOFT_TIMER_MAX && id >= 0) {
		timers_array[id].state_ = SOFT_TIMER_IDLE;
	}
	xTaskResumeAll();
}

void soft_timer_start(int8_t id,uint32_t count) {
	
	if(id < SOFT_TIMER_MAX && id >= 0) {
		vTaskSuspendAll();
		if(timers_array[id].state_ == SOFT_TIMER_STOPPED) {
			timers_array[id].count_ = count;
			timers_array[id].match_ = timers_array[id].period_ + (uint32_t)xTaskGetTickCount();
			timers_array[id].state_ = SOFT_TIMER_RUNNING;
		}
		xTaskResumeAll();
	}

}

void soft_timer_stop(int8_t id) {

	if(id < SOFT_TIMER_MAX && id >= 0) {
		vTaskSuspendAll();
		timers_array[id].state_ = SOFT_TIMER_STOPPED;
		xTaskResumeAll();
	}
}

void soft_timer_restart(int8_t id,uint32_t count) {
	soft_timer_stop(id);
	soft_timer_start(id,count);
}

uint8_t soft_timer_get_state(int8_t id) {
	
	if(id >= SOFT_TIMER_MAX)
		return SOFT_TIMER_ERROR;
	
	return timers_array[id].state_;
}

void soft_timer_check(soft_timer_t *timer) {
	
	if(timer->state_ != SOFT_TIMER_RUNNING)
		return ;
	
	uint32_t tick_cnt_ = xTaskGetTickCount();
	if((tick_cnt_ - timer->match_) < (SOFT_TIMER_TICK_MAX / 2)) {
		timer_callback callback = timer->callback_;
		callback(timer->param_);
		
		if(timer->count_ != SOFT_TIMER_RUN_FOREVER) {
			if(timer->count_ > 0) {
				timer->count_--;
			} else {
				timer->state_ = SOFT_TIMER_STOPPED;
				return ;
			}
		}
		timer->match_ = tick_cnt_ + timer->period_;
	}
}

void soft_timer_update() {
	
	for(int i = 0; i < SOFT_TIMER_MAX;i++) {
		soft_timer_check(&timers_array[i]);
	}
}

void soft_timer_repair(int8_t id,uint32_t period,timer_callback callback,void *param) {

	if(id < 0 || id >= SOFT_TIMER_MAX)
		return ;
	
	vTaskSuspendAll();
	timers_array[id].state_ = SOFT_TIMER_STOPPED;
	timers_array[id].period_ = period;
	timers_array[id].callback_ = callback;
	timers_array[id].param_ = param;
	xTaskResumeAll();
}


